﻿package com.dcliment.jukebox.controllers
{
	
	import com.dcliment.controllers.MetricsController;
	import com.dcliment.elements.MetricsElement;
	import com.dcliment.jukebox.JukeBox;
	import com.dcliment.jukebox.display.views.JukeBoxView;
	import com.dcliment.jukebox.events.JukeBoxEvent;
	import com.dcliment.jukebox.models.ContentControllerModel;
	import com.dcliment.jukebox.models.JukeBoxModel;
	import com.dcliment.jukebox.models.NavModel;
	import com.dcliment.jukebox.models.OverlayModel;
	import com.dcliment.jukebox.models.TimerModel;
	import com.dcliment.models.MetricsModel;
	import com.dcliment.utils.XMLUtils;
	import com.moody.loaders.XMLLoader;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.ui.Mouse;

	/**
	 * AppController instantiates these controllers
	 *  > MetricsController :: gives it model and starts session
	 *  > NavController :: this controls AppModel.id -- anytime it automatically cycles through it tells the navController to click the next button and set the AppModel.id
	 *  > ContentController :: preloads all swfs as well as controls which one is active at anymoment
	 *  > TimerController :: creates timer for countdown as well as controls play pause
	 *  
	 * @author dcliment
	 * version 1.0
	 * 
	 */	
	public class JukeBoxController extends EventDispatcher implements IJukeBox
	{
		private var _jukeBoxModel:JukeBoxModel;
		private var _jukeBoxView:JukeBoxView;
		//
		private var _xmlLoader:XMLLoader;
		// Models
		private var _metricsModel:MetricsModel
		private var _navModel:NavModel;
		private var _contentControllerModel:ContentControllerModel;
		private var _timerModel:TimerModel;
		private var _overlayModel:OverlayModel;
		// Controllers
		private var _metricsController:MetricsController;
		private var _navController:JukeNavController;
		private var _contentController:JukeContentController;
		private var _timerController:TimerController;
		private var _overlayController:JukeOverlayController;
		private var _overlayControllerList:Array;
		
		public function JukeBoxController($model:JukeBoxModel, $view:JukeBoxView)
		{
			_jukeBoxModel 	= $model;
			_jukeBoxView 	= $view;
			//
			_jukeBoxModel.addEventListener(JukeBoxEvent.ID_CHANGE, onIdChange, false, 0, true);
			
			// CONTROLLERS
			_metricsController 	= MetricsController.getInstance();
			_navController 		= new JukeNavController(_jukeBoxModel, _jukeBoxView.viewNav);
			_contentController 	= new JukeContentController(_jukeBoxModel, _jukeBoxView.viewContent, this);
			_timerController 	= new TimerController(_jukeBoxModel, _jukeBoxView.viewTimer, this);
			//_overlayController 	= new JukeOverlayController(_jukeBoxModel, _jukeBoxView.viewOverlay, this);
			
			// ON CLOSE of APPLICATION
			try
			{
				_jukeBoxModel.theStage.nativeWindow.addEventListener(Event.CLOSING, onAppClose, false, 0, true);
			}
			catch(e:Error)
			{
				// DO NOTHING
			}
			
			// INIT event 
			_contentController.addEventListener(JukeBoxEvent.INIT, onInit, false, 0, true);
			
		}
		/**
		 * Theoretically this will end the session as you close the window
		 *  
		 * @param e
		 * 
		 */		
		private function onAppClose(e:Event):void
		{
			trace("AppController.onAppClose() ::: FIRED :::");
			
			_metricsController.endSession();
		}
		
		public function loadXML($url:String):void
		{
			_xmlLoader = new XMLLoader($url);
			_xmlLoader.addEventListener(Event.COMPLETE, onXMLLoaded, false, 0, true);
			_xmlLoader.load()
		}
		public function reset():void
		{
			//??
		}
		/**
		 * Grabs the time for the specific content from the ContentController
		 * 
		 * @return  
		 */		
		public function get time():Number
		{
			return _contentController.contentTime;
		}
		/**
		 * When automatically cycling through pages this determins what page is next and if so which button shoudl be actived 
		 * 
		 */		
		public function nextPage():void
		{
			var n:int;
			
			if(_jukeBoxModel.id == _jukeBoxModel.totalPages - 1)
			{
				n = 0;
			}
			else
			{
				n = _jukeBoxModel.id;
				n++;
			}
			
			_navController.activateButton(n);
		}
		/**
		 * This Pauses the Timer as well as Pauses the Content 
		 * 
		 */		
		public function pauseApp():void
		{
			if(_jukeBoxModel.playState)
				_timerController.pauseController();
		}
		/**
		 * Resumes the initial timer 
		 * 
		 */		
		public function resumeApp():void
		{
			trace("RESUME APP FIRED");
			if(!_jukeBoxModel.playState)
				_timerController.playController();
		}
		////////
		// Private Functions
		////////
		private function onXMLLoaded(e:Event):void
		{
			_xmlLoader.removeEventListener(Event.COMPLETE, onXMLLoaded);
			
			// XML
			var xml:XML = _xmlLoader.xml;

			// MODELS
			var settingsNav:XMLList	= XMLUtils.getXMLNode(xml, "navSettings", true);
			//
			_navModel 						= new NavModel();
			_navModel.posX 					= XMLUtils.getXMLAttribute(settingsNav.position, "x", Number, 0, true);
			_navModel.posY 					= XMLUtils.getXMLAttribute(settingsNav.position, "y", Number, 0, true);
			_navModel.buttonSpacing			= XMLUtils.getXMLAttribute(settingsNav.navButton, "spacing", Number, NaN, false); // one of these is nessesssary
			_navModel.numOfVisibleButtons 	= XMLUtils.getXMLAttribute(settingsNav.navButton, "numOfVisible", Number, NaN, true); // one of these is nessessary
			_navModel.button0_x 	        = XMLUtils.getXMLAttribute(settingsNav.navButton, "button0_x", Number, NaN, false); 
			_navModel.button0_y 	        = XMLUtils.getXMLAttribute(settingsNav.navButton, "button0_y", Number, NaN, false); 
			
			_navModel.buttonLinkage			= XMLUtils.getXMLNodeValue(settingsNav, "buttonLinkageName", String, null, true);
			_navModel.navList				= XMLUtils.getXMLNode(xml, "nav", true);
			_navModel.navLabelColorOn		= XMLUtils.getXMLAttribute(settingsNav.buttonOnState, "color", Number, null, false);
			
			var metricsXML:XMLList = XMLUtils.getXMLNode(xml.appSettings, "metrics", true);
			//
			_metricsModel 				= new MetricsModel();
			_metricsModel.doesRecord 	= XMLUtils.getXMLAttribute(metricsXML, "doesRecord", Boolean, null, true);
			_metricsModel.dbPath 		= XMLUtils.getXMLAttribute(metricsXML, "dbPath", String, null, true);
			_metricsModel.deviceCode 	= XMLUtils.getXMLAttribute(metricsXML, "DeviceCode", String, null, true);
			_metricsModel.appCode 		= XMLUtils.getXMLAttribute(metricsXML, "AppCode", String, null, true);
			
			var settingsContent:XMLList = XMLUtils.getXMLNode(xml, "contentSettings", true);
			//
			_contentControllerModel 			= new ContentControllerModel();
			_contentControllerModel.posX 		= XMLUtils.getXMLAttribute(settingsContent.position, "x", Number, 0, false);
			_contentControllerModel.posY 		= XMLUtils.getXMLAttribute(settingsContent.position, "y", Number, 0, false);
			_contentControllerModel.width 		= XMLUtils.getXMLAttribute(settingsContent.size, "w", Number, _jukeBoxModel.theStage.stageWidth, false);
			_contentControllerModel.hieght 		= XMLUtils.getXMLAttribute(settingsContent.size, "h", Number, _jukeBoxModel.theStage.stageHeight, false);
			_contentControllerModel.shouldMask	= XMLUtils.getXMLAttribute(settingsContent.size, "shouldMask", Boolean, true, false);
			_contentControllerModel.pagesList 	= XMLUtils.getXMLNode(xml, "page", true);
			_contentControllerModel.tSpd		= XMLUtils.getXMLAttribute(settingsContent.tween, "speed", Number, 1, false);
			_contentControllerModel.tEasing		= XMLUtils.getXMLAttribute(settingsContent.tween, "easing", String, "Linear.easeNone", false);
			
			var settingsTimer:XMLList = XMLUtils.getXMLNode(xml, "timerSettings", true);
			//
			_timerModel 					= new TimerModel();
			_timerModel.posX 				= XMLUtils.getXMLAttribute(settingsTimer.position, "x", Number, 0, false);
			_timerModel.posY 				= XMLUtils.getXMLAttribute(settingsTimer.position, "y", Number, 0, false);
			_timerModel.pauseTimerDelay 	= XMLUtils.getXMLNodeValue(settingsTimer, "pauseTimer", Number, null, true);
			_timerModel.showTimerView		= XMLUtils.getXMLAttribute(settingsTimer, "showTimerControls", Boolean, true, false);
			var ppButtonMetrics:XMLList 	= XMLUtils.getXMLNode(settingsTimer, "ppButtonMetrics", true);
			//
			_timerModel.ppButtonToken		= XMLUtils.getXMLAttribute(ppButtonMetrics, "metricsToken", String, null, true);
			_timerModel.ppObjectStateOn		= XMLUtils.getXMLAttribute(ppButtonMetrics, "objectStateOn", String, null, true);
			_timerModel.ppObjectStateOff	= XMLUtils.getXMLAttribute(ppButtonMetrics, "objectStateOff", String, null, true);
			
			var settingsOverlay:XMLList = XMLUtils.getXMLNode(xml, "overlaySettings", true);
			

			// Check and balances
			if(_contentControllerModel.pagesList.length() != _navModel.navList.length())
				throw new Error("AppController ERROR :: The amouunt of page nodes does not equal the amount of nav nodes int he XML");
			
			// APPMODEL
			_jukeBoxModel.totalPages = _contentControllerModel.pagesList.length();
			_jukeBoxModel.hideCursor = XMLUtils.getXMLNodeValue(xml.appSettings, "hideCursor", Boolean, false, false);
	

			// Metrics Controller
			_metricsController.setModel(_metricsModel);
			_metricsController.init();
			_metricsController.endSession();
			_metricsController.startSession();
			// CONTROLLERS
			_navController.setup(_navModel);
			_contentController.setup(_contentControllerModel);
			_timerController.setup(_timerModel);
			
			//EDG 2013.09.05
			//OVERLAYS
			//we need to accommodate for 0,1, or more overlay tabs
			_overlayControllerList = new Array();
			for each(var overlayNode:XML in settingsOverlay.*){

				var overlayModel:OverlayModel = new OverlayModel();
				overlayModel.clipName   = XMLUtils.getXMLAttribute(overlayNode.clip, "name", String, null, true);
				overlayModel.label		= XMLUtils.getXMLNodeValue(overlayNode, "label", String, null, true);
				overlayModel.posX 		= XMLUtils.getXMLAttribute(overlayNode.position, "x", Number, 0, true);
				overlayModel.posY 		= XMLUtils.getXMLAttribute(overlayNode.position, "y", Number, 0, true);
				overlayModel.tweenX 	= XMLUtils.getXMLAttribute(overlayNode.tween, "x", Number, 0, true);
				overlayModel.tweenY 	= XMLUtils.getXMLAttribute(overlayNode.tween, "y", Number, 0, true);
				overlayModel.tweenSpd 	= XMLUtils.getXMLAttribute(overlayNode.tween, "speed", Number, 1, false);
				overlayModel.tweenEase  = XMLUtils.getXMLAttribute(overlayNode.tween, "easing", String, "Linear.easeNone", false);
				overlayModel.token		= XMLUtils.getXMLAttribute(overlayNode.metrics, "metricsToken", String, null, true);
				
				var overlayContent:XMLList = XMLUtils.getXMLNode(overlayNode, "content", false);
				
				
				if(overlayContent)
				{
					overlayModel.contentSrc 	= XMLUtils.getXMLAttribute(overlayContent, "src", String, null, true);
					overlayModel.contentX		= XMLUtils.getXMLAttribute(overlayContent, "x", Number, 0, false);
					overlayModel.contentY 		= XMLUtils.getXMLAttribute(overlayContent, "y", Number, 0, false);
				}
				
				
				var overlayController:JukeOverlayController = new JukeOverlayController(_jukeBoxModel, _jukeBoxView.viewOverlay, this);
				overlayController.setup(overlayModel);
				
				
				
				//------------------------------------
				// EVENTS
				overlayController.addEventListener(JukeOverlayController.CLOSE, onOverlayClose, false, 0,true);
				overlayController.addEventListener(JukeOverlayController.OVERLAY_INTERACTED, function():void{_timerController.resetPauseTimer();});
				
				_overlayControllerList.push(overlayController);
			}
			//_overlayController.setup(_overlayModel);
			
			//------------------------------------
			// EVENTS
			//_overlayController.addEventListener(JukeOverlayController.CLOSE, onOverlayClose, false, 0,true);
			//_overlayController.addEventListener(JukeOverlayController.OVERLAY_INTERACTED, function():void{_timerController.resetPauseTimer();});
			
			//-------------------------------------
			// INIT()
			
			if(_jukeBoxModel.hideCursor)
				Mouse.hide();
			
		}
		//--------------------------------------------
		// EVENT LISTENERS
		private function onInit(e:JukeBoxEvent):void
		{
			_contentController.removeEventListener(JukeBoxEvent.INIT, onInit);
			
			_navController.activateButton(0);
		}
		private function onIdChange(e:JukeBoxEvent):void
		{
			
		}
		private function onOverlayClose(e:Event):void
		{
			_metricsController.recordPage(_navController.activeToken);
		}
		//-------------------------------------------
		// TRACK
		//
		public function track(m:MetricsElement):void
		{
			if(m.type == MetricsElement.PAGE)
				_metricsController.recordPage(m.token);
			else if(m.type == MetricsElement.EVENT)
				_metricsController.recordObjectEvent(m.token, m.objectState);
			else
				throw new Error("JukeBoxController.track() ERROR :: m.type = " + m.type + " for m.token = " + m.token + " :: is not an appropriate type");
		}
	}
}